
/*

H3: SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSHH  extended size/header type
H2: CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCHH extended class/header type
H1: GGGHHHHHHHHHHHHCCCCCFFFFSSSSSSHH gcState/hash/compactclass/format/compactsize/header type
Contents

header type: 0=3 word header, 1=2 word header, 2=free space, 3=1 word header
compact class: 0=has extended class, else=index into compact class array
object format: 
        0      no fields
        1      fixed fields only (all containing pointers)
        2      indexable fields only (all containing pointers)
        3      both fixed and indexable fields (all containing pointers)
        4      both fixed and indexable weak fields (all containing pointers).

        5      unused
        6      indexable word fields only (no pointers)
        7      indexable long (64-bit) fields (only in 64-bit images)
 
    8-11      indexable byte fields only (no pointers) (low 2 bits are low 2 bits of size)
   12-15     compiled methods: 
                   # of literal oops specified in method header,
                   followed by indexable bytes (same interpretation of low 2 bits as above)

compact size: 0=has extended size, else=size

sizes: length of object contents in words + 1

*/

int isPointers(int object)
{
	return instanceSpec(classOf(object)) < 6;
}
int indexIfCompact(int klass)
{
	int format = mustUnpackSmInt(slotOf(klass,3));
	return (format >> 11) & 0x1F;
}
int instanceSpec(int klass)
{
	int format = mustUnpackSmInt(slotOf(klass,3));
	return (format >> 7) & 0xF;
}
int instanceSize(int klass)
{
	int format = mustUnpackSmInt(slotOf(klass,3));
	return ((format >> 10) & 0xC0) + ((format >> 1) & 0x3F) - 1;
}

void setMark(int oop) { *(int*)oop |= (1<<31); }
void clearMark(int oop) { *(int*)oop &= ~(1<<31); }
int isMarked(int oop) { return *(int*)oop & (1<<31); }

int methodClass(int methodOop)
{
	int header = unpackSmInt(slotOf(methodOop, 1)); 
	int nLiterals = (header >> 9) & 0xFF;
	int assoc = slotOf(methodOop, nLiterals+1);
	return slotOf(assoc, 2);
}
int methodSelector(int methodOop)
{
	int header = unpackSmInt(slotOf(methodOop, 1)); 
	int nLiterals = (header >> 9) & 0xFF;
	int methodProp = slotOf(methodOop, nLiterals+1-1);
	return slotOf(methodProp, 3);
}

int isA(int oop, int class)
{
	int myClass = classOf(oop);
	while(myClass != nil)
	{
		if(myClass == class) return 1;
		myClass = slotOf(myClass, 1); //superclass
	}
	return 0;
}

inline int inSmIntRange(int value) 
{
	return (value >= -0x40000000) && (value <= 0x3FFFFFFF);
}

inline int isSmInt(int oop)
{
	return oop & 1;
}

inline int packSmInt(int value)
{
	if(inSmIntRange(value)) return (value << 1) | 1;
	success = 0;
	return 0;
}

inline int unpackSmInt(int oop)
{
	if(isSmInt(oop)) return oop >> 1;
	success = 0;
	return 0;
}

int mustUnpackSmInt(int oop)
{
#ifdef BOUNDS_CHECK
	ASSERT( isSmInt(oop), "Attempt to unpack an oop that is not a SmallInteger" );
#endif
	return oop >> 1;
}

unsigned int unpackPos32(int oop)
{
	if( isSmInt(oop) ) {
		int value = unpackSmInt(oop);
		if(value>=0) return value;
	}
	if( classOf(oop)==LargePositiveInteger && sizeOf(oop)==1 ){
		return *(unsigned int*)(oop+4); //BOGUS check endianess
	}
	
	success = 0;
	return 0;
}

int packPos32(unsigned int value)
{
	if(value <= 0x3FFFFFFF) return packSmInt((int)value);
	
	int lpi = clone(LargePositiveIntegerPrototype);
	*(unsigned int*)(lpi+4) = value; //BOGUS check endianess
	return lpi;
}

int packSigned32(int value)
{
	if(inSmIntRange(value)) return packSmInt((int)value);
	
	int class, obj;
	
	if( value < 0 ) { class = LargeNegativeInteger; value = 0 - value; }
	else class = LargePositiveInteger;
	
	obj = instantiateN(class, 1);
	*(int*)(obj+4) = value; //BOGUS check endianess
	return obj;
}

int classOf(int oop)
{
	if( isSmInt(oop) ) return SmallInteger;
	
	int header = *(int*)oop;
	int cc = (header >> 12) & 0x1F; //5 bits
	
	if(cc==0) return (*(int*)(oop-4)) & 0xFFFFFFFC; //extended class is H2, clear lower 2 bits
	return slotOf(compactClassesArray, cc);
}

int sizeOf(int oop)
{
	if( isSmInt(oop) ) return 0;

	int header = *(int*)oop;
	int size = (header >> 2) & 0x3F; //6 bits
	
	if(size==0) return ((*(int*)(oop-8)) >> 2) - 1; //extended size in H3
	return size - 1;
	//note: subtract 1 because these size fields include H1
}

int headerSizeOf(int oop)
{
	int header = *(int*)oop;
	
	switch(header&3){
		case 0: //3-word header
			return 3;
		case 1: //2-word header
			return 2;
		case 2: //free space marker
			PANIC("unexpected free space in headerSizeOf");
		case 3: //1-word (compact) header
			return 1;
	}
}

int formatOf(int oop)
{
	return (*(int*)oop >> 8) & 0xF;
}

int gcOf(int oop)
{
	return *(int*)oop >> 29;
}

int hashOf(int oop)
{
	return (*(int*)oop >> 17) & 0xFFF;
}

inline int slotOf(int oop, int index)
{
#ifdef BOUNDS_CHECK
	if( index < 1 || index > sizeOf(oop) )
	{
		printf("Index %d in\n", index);
		printFullObject(oop);
		PANIC("slotOf access beyond bounds of object");
	}
#endif
	return *(int*)(oop+index*4);
}

int byteSlotOf(int oop, int index)
{
#ifdef BOUNDS_CHECK
	if( index < 1 || index/4 > sizeOf(oop) )
	{
		printf("Index %d in\n", index);
		printFullObject(oop);
		PANIC("byteSlotOf access beyond bounds of object");
	}
#endif
	return *(unsigned char*)(oop+3+index);
}

void setClassOf(int oop, int klass)
{
	PANIC("setClassOf not implemented");
}

void setSizeOf(int oop, int size)
{
	PANIC("setClassOf not implemented");
}

void setFormatOf(int oop, int fmt)
{
	PANIC("setFormatOf not implemented");
}

void setGcOf(int oop, int gcBits)
{
	PANIC("setGcOf not implemented");
}

void setHashOf(int oop, int hash)
{
	PANIC("setHashOf not implemented");
}

void setSlotOf(int oop, int index, int value)
{
#ifdef BOUNDS_CHECK
	if( index < 1 || index > sizeOf(oop) )
	{
		printf("Index %d in\n", index);
		printFullObject(oop);
		PANIC("slotOf access beyond bounds of object");
	}
#endif
	*(int*)(oop+index*4) = value;
}

void setByteSlotOf(int oop, int index, int value)
{
#ifdef BOUNDS_CHECK
	ASSERT( value >= 0 && value <= 255, "setByteSlot of passed non-byte value");
	
	if( index < 1 || index/4 > sizeOf(oop) )
	{
		printf("Index %d in\n", index);
		printFullObject(oop);
		PANIC("byteSlotOf access beyond bounds of object");
	}
#endif
	*(unsigned char*)(oop+3+index) = value;
}

int instSizeOf(int object)
{
	int f;
	f = unpackSmInt(slotOf(classOf(object),3));
	return ((f>>1) & 0x3F) + ((f>>10) & 0xC0) - 1;
}
